/** 计数器(Counter)封装
 *
 * Feature
 *  - 支持位宽可设置[[size]]
 *  - 支持多口并发访问[[num]]
 *  - 支持循环计数模式
 *    - 最小值为`io.min` (Include)
 *    - 最大值为`io.max` (Include)
 *  - 支持饱和计数模式
 *    - 最小值为`io.min` (Include)
 *    - 最大值为`io.max` (Include)
 *  - 支持上下溢告警
 *    - 计数器的值大于`io.max`时，上报overflow错误
 *    - 计数器的值小于`io.min`时，上报underflow错误
 *  - 支持超范围告警
 *    - 超范围指计数器当拍的变化量 > max-min的范围，则上报oversopce错误
 *    - 这时，计数器的内容不可预期
 *
 *
 * @groupname IO
 * @groupname Const
 * @groupname module
 * @groupname encapuse
 */
package comlib.counter {


import chisel3._
import chisel3.util._
import comlib.reduce 


/** 计数器模式选择 
 *
 * @group Const
 */
object CNT_MODE {
  val SZ = 1
  /** 循环计数模式 */
  def LOOP = 0.U(SZ.W)
  /** 饱和计数模式 */
  def SAF = 1.U(SZ.W)
}

/** 计数器计数命令 
 *
 * @group Const 
 */
object CNT_CMD {
  val SZ = 2
  /** 无效命令 */
  def INVALID = 0.U(SZ.W)
  /** Increase命令 */
  def INC = 1.U(SZ.W)
  /** Decrease命令 */
  def DEC = 2.U(SZ.W)
} 

/** Counter操作数接口定义
 * @param init 操作数模板
 *
 * @group IO
 */
class OperatorIO[T<:Bits with Num[T]](init:T) extends Bundle {
  /** 操作数值 */
  val value = Output(chiselTypeOf(init))

  override def cloneType = new OperatorIO(init).asInstanceOf[this.type]
} 

/** Adder接口定义 
 * @param init 操作数模板
 * 
 * @group IO
 */
class AdderIO[T<:Bits with Num[T]](init:T) extends OperatorIO(init) {
  /** 操作数是否increase标识
   *  - true.B: increase
   *  - false.B: decrease
   */
  val inc = Output(Bool())
  /** 上溢中断：相加结果操过了`size`可以表示的范围 */
  val overflow = Output(Bool())
  /** 下溢中断：相减的结果小于0 */
  val underflow = Output(Bool())

  override def cloneType = new AdderIO(init).asInstanceOf[this.type]
}

/** AdderIO的类封装
 * @group IO
 */
object AdderIO{
  /** 参数参考[[AdderIO]]接口定义 */
  def apply[T<:Bits with Num[T]](init:T, inc:Bool, value:T, overflow:Bool=false.B, underflow:Bool=false.B) : AdderIO[T] = {
    val io = Wire(new AdderIO(init))
    io.inc := inc
    io.value := value 
    io.overflow := overflow 
    io.underflow := underflow
    io
  }
}

/** Command接口定义
 * @param init 操作数模板
 *
 * @group IO
 */
class CommandIO[T<:Bits with Num[T]](init:T) extends OperatorIO(init){
  /** 操作数命令。参考[[CNT_CMD]] */
  val cmd = Output(UInt(CNT_CMD.SZ.W))

  override def cloneType = new CommandIO(init).asInstanceOf[this.type]
}

/** CommandIO的类封装
 * @group IO
 */
object CommandIO{
  /** 参数参考[[CommandIO]]接口定义 */
  def apply[T<:Bits with Num[T]](init:T, cmd:UInt, value:T) : CommandIO[T] = {
    val io = Wire(new CommandIO(init))
    io.cmd := cmd
    io.value := value 
    io
  }
}

/** 计数器组命令IO
 * @group IO
 */
class CommandsIO[T<:Bits with Num[T]](init:T, cnum:Int) extends CommandIO(init) {
  /** 计数器序号 */
  val cid = Output(UInt(log2Up(cnum).W))

  override def cloneType = new CommandsIO(init, cnum).asInstanceOf[this.type]
}

/** Counter接口定义
 * @param init 操作数模板
 *
 * @group IO
 */
class CommonCounterIO[T<:Bits with Num[T]](init:T) extends Bundle{
  /** 计数模式。参考[[CNT_MODE]] */
  val mode = Input(UInt(1.W))

  /** 强制置位使能 */
  val force = Input(Bool())
  /** 强制置位值 */
  val forceValue = Input(chiselTypeOf(init))

  /** 清零使能 */
  val clear = Input(Bool())
  /** 清零值 */
  val clearValue = Input(chiselTypeOf(init))

  /** 计数器允许的最大值 */
  val min = Input(chiselTypeOf(init))
  /** 计数器允许的最小值 */
  val max = Input(chiselTypeOf(init))

  /** 计数器输出值 */
  val value = Output(chiselTypeOf(init))
  /** 上溢中断 */
  val overflow = Output(Bool())
  /** 下溢中断 */
  val underflow = Output(Bool())
  /** 超范围中断 */
  val overscope = Output(Bool())

  override def cloneType = new CommonCounterIO(init).asInstanceOf[this.type]  
}

/** 计数器IO
 * @param size 计数器比特位宽
 * @param num 计数口个数
 *
 * @group IO
 */
class CounterIO[V<:Bits with Num[V], O<:Bits with Num[O]](v:V, op:O, num:Int) extends CommonCounterIO(v) {

  /** 计数命令。参考[[CommandIO]] */
  val cmds = Vec(num, Flipped(new CommandIO(op)))

  override def cloneType = new CounterIO(v, op, num).asInstanceOf[this.type]
}

/** 计数器组接口
 * @group IO
 */
class CountersIO[V<:Bits with Num[V], O<:Bits with Num[O]](v:V, op:O, num:Int, cnum:Int) extends CommonCounterIO(v) {
  /** 计数命令。参考[[CommandsIO]] */
  val cmds = Vec(num, Flipped(new CommandsIO(op, cnum)))

  override def cloneType = new CountersIO(v, op, num, cnum).asInstanceOf[this.type]
}

/** 计数器IO
 * @param size 计数器比特位宽
 * @param num 计数口个数
 *
 * @group IO
 */
class CountIO[V<:Bits with Num[V], O<:Bits with Num[O]](v:V, op:O, num:Int) extends CounterIO(v,op,num) {

  /** 计数初始值 */
  val load = Input(chiselTypeOf(v))

  override def cloneType = new CountIO(v, op, num).asInstanceOf[this.type]
}





/** Adder实现
 * @param init 操作数模板
 *
 * @group module
 */
class AdderImpl[T<:Bits with Num[T]](init:T) extends MultiIOModule {

  val in0 = IO( Flipped(new AdderIO(init)) )
  val in1 = IO( Flipped(new AdderIO(init)) )
  val out = IO( new AdderIO(init))

  //==== Initial output
  val of = in0.overflow | in1.overflow
  val uf = in0.underflow | in1.underflow
  out.overflow := false.B 
  out.underflow := false.B

  //==== Count
  when( in0.inc ^ in1.inc ){
    when( in0.value >= in1.value ){
      out.value := in0.value - in1.value
      out.inc := in0.inc
    }.otherwise{
      out.value := in1.value - in0.value
      out.inc := in1.inc
    }
  }.otherwise{
    val v = Cat(0.U(1.W), in0.value) + Cat(0.U(1.W), in1.value)
    val size = init.getWidth
    out.value := v(size-1, 0)
    out.inc := in0.inc
    out.overflow := (v(size) & in0.inc) | of
    out.underflow := (v(size) & !in0.inc) | uf
  }

}

/** Adder Module的类封装
 * @group module
 */
object AdderImpl {
  /** Adder函数封装
   * @param size 操作数位宽
   * @param in0 第一个操作数
   * @param in1 第二个操作数
   * @return AdderImpl的返回`out`接口
   *
   */
  def apply[T<:Bits with Num[T]](init:T)( in0: AdderIO[T], in1: AdderIO[T] ): AdderIO[T] = {
    val adder = Module(new AdderImpl(init))
    adder.in0.inc := in0.inc
    adder.in0.value := in0.value
    adder.in0.overflow := in0.overflow
    adder.in0.underflow := in0.underflow
    adder.in1.inc := in1.inc
    adder.in1.value := in1.value
    adder.in1.overflow := in1.overflow
    adder.in1.underflow := in1.underflow
    adder.out
  }
}


/** 计数器实现Module
 *
 * 接口参考[[CountIO]]
 * 
 * @param v 计数器值构造模板(类型&位宽)。当`isCounter=true`时，为计数器的初始值
 * @param op 操作数模板(类型&位宽)
 * @param num 操作数个数
 * @param isCounter 是否带寄存器的计数器标识
 * @return 计数器Module
 *
 * @group module
 */
class CountImpl[V<:Bits with Num[V], O<:Bits with Num[O]](v:V, op:O, num:Int, isCounter:Boolean) extends Module {

  val io = IO( new CountIO(v,op,num) )  //接口
  val in = if( isCounter ) RegInit(v) else io.load

  private val cmds = io.cmds.map{ case x => AdderIO[O](op, 
                                              x.cmd===CNT_CMD.INC, 
                                              Mux(x.cmd===CNT_CMD.INVALID, 0.U.asTypeOf(chiselTypeOf(op)), x.value)) }
  val adder_out = reduce.binaryTree( AdderImpl(op), cmds )

  //==== Init
  io.overflow := false.B 
  io.underflow := false.B
  io.overscope := io.max - io.min < adder_out.value.asTypeOf(v)
  val load = Mux( io.clear, io.clearValue, in )
  val out = Wire(chiselTypeOf(v))
  
  //==== Count
  when( adder_out.inc ){
    io.overflow := adder_out.overflow | ( io.max - load < adder_out.value.asTypeOf(v) )
    out := Mux( io.overflow,
                  Mux( io.mode===CNT_MODE.LOOP, 
                    adder_out.value.asTypeOf(v) - (io.max - load) + io.min - 1.U.asTypeOf(chiselTypeOf(v)), io.max ),
                  adder_out.value.asTypeOf(v) + load )
  }.otherwise{ 
    io.underflow := adder_out.underflow | ( load - io.min < adder_out.value.asTypeOf(v) )
    out := Mux( io.underflow,
                  Mux( io.mode===CNT_MODE.LOOP,
                    io.max - (adder_out.value.asTypeOf(v) - (load - io.min)) + 1.U.asTypeOf(chiselTypeOf(v)), io.min ),
                  load - adder_out.value.asTypeOf(v) )
  }

  //==== force
  when( io.force ){ out := io.forceValue }

  if( isCounter ){
    in := out
    io.value := in
  }else
    io.value := out


  /** 计数器输出值 */
  def value() = io.value 
  /** 上溢中断：计数器运算后的值向上超出了`max`的值 */
  def overflow() = io.overflow 
  /** 下溢中断：计数器运算后的值向下超出了`min`的值 */
  def underflow() = io.underflow
  /** 超范围中断: 计数器档次计算的增加量(或者减少量)超过了`max`-`min`的范围 */
  def overscope() = io.overscope

  /** 设置上边界 */
  def setMax(max:V) = {
    io.max := max 
    this
  }

  /** 设置下边界 */
  def setMin(min:V) = {
    io.min := min 
    this
  }

  /** 设置force值 */
  def force(en:Bool, value:V):this.type = {
    io.force := en 
    io.forceValue := value 
    this
  }
  def force(en:Bool):this.type = force(en,0.U.asInstanceOf[V])
  def force(value:V):this.type = force(true.B, value)
  def force():this.type = force(true.B)

  /** 设置clear值 */
  def clear(en:Bool, value:V):this.type = {
    io.clear := en 
    io.clearValue := value 
    this
  }
  def clear(en:Bool):this.type = clear(en,0.U.asInstanceOf[V])
  def clear(value:V):this.type = clear(true.B, value)
  def clear():this.type = clear(true.B)
}

/** Counter封装类
 * @group module
 */
object Count{

  /** 实例化[[CountImpl]]，并设置默认输入 
   *
   * 默认输入信号设置
   *  - force: false.B
   *  - forceValue: 0.V
   *  - clear: false.B
   *  - clearValue: 0.V
   *  - cmds(i).cmd: CNT_CMD.INC
   *  - cmds(i).value: 1.V
   * 
   * @param v 计数器值模板(类型&位宽)。`isCounter`=true时，标识初始值；否则标识io.load信号
   * @param max 计数器最大值。若max.getWidth=0，则使用v.getWidth个全1的值作为最大值
   * @param min 计数器最小值。若min.getWidth=0，则使用v.getWidth个全0的值作为最小值
   * @param num 计数器操作数个数。
   * @param mode 计数器模式。参考[[CNT_MODE]]
   * @param op 计数器操作数模板(类型&位宽)。若op.getWidth=0，则使用v来做模板
   * @param isCounter 是否寄存计数器标识。参见[[CountImpl]]
   * @return CountImpl Module实例
   */
  def apply[V<:Bits with Num[V], O<:Bits with Num[O]]( v:V, max:V, min:V, num:Int, mode:UInt, op:O, isCounter:Boolean ) : CountImpl[V,O] = {
   
    val opn = 
      if( op.getWidth==0 ) v.asInstanceOf[O]
      else op
    val cnt = Module(new CountImpl[V,O](v,opn,num, isCounter))
    cnt.io.load := v
    cnt.io.mode := mode
    cnt.io.force := false.B
    cnt.io.forceValue := 0.U.asTypeOf(chiselTypeOf(v))
    cnt.io.clear := false.B
    cnt.io.clearValue := 0.U.asTypeOf(chiselTypeOf(v))
    
    if( min.getWidth==0 ) cnt.io.min := 0.U.asTypeOf(chiselTypeOf(v)) 
    else cnt.io.min := min
    
    if( max.getWidth==0 ) cnt.io.max := ~(0.U).asTypeOf(chiselTypeOf(v))
    else cnt.io.max := max

    for( i <- 0 until num ){
      cnt.io.cmds(i).cmd := CNT_CMD.INC 
      cnt.io.cmds(i).value := 1.U.asTypeOf(chiselTypeOf(op))
    }

    cnt
  }

  /** 0~log2Cell(load)循环计数 */
  def apply[V<:Bits with Num[V], O<:Bits with Num[O]]( load:V ):CountImpl[V,O]
    = apply( load, 0.U(0.W).asInstanceOf[V], 0.U(0.W).asInstanceOf[V], 1, CNT_MODE.LOOP, 0.U(0.W).asInstanceOf[O], false )

  /** 0~max循环计数 */
  def apply[V<:Bits with Num[V], O<:Bits with Num[O]]( load:V, max:V ):CountImpl[V,O]
    = apply( load, max, 0.U(0.W).asInstanceOf[V], 1, CNT_MODE.LOOP, 0.U(0.W).asInstanceOf[O], false )

  /** min~max饱和计数 */
  def apply[V<:Bits with Num[V], O<:Bits with Num[O]]( load:V, max:V, min:V ):CountImpl[V,O]
    = apply( load, max, min, 1, CNT_MODE.SAF, 0.U(0.W).asInstanceOf[O], false )

  /** 0~max饱和计数 */
  def apply[V<:Bits with Num[V], O<:Bits with Num[O]]( load:V, max:V, num:Int ):CountImpl[V,O]
    = apply( load, max, 0.U(0.W).asInstanceOf[V], num, CNT_MODE.SAF, 0.U(0.W).asInstanceOf[O], false )

  /** min~max饱和计数 */
  def apply[V<:Bits with Num[V], O<:Bits with Num[O]]( load:V, max:V, min:V, num:Int ):CountImpl[V,O]
    = apply( load, max, min, num, CNT_MODE.SAF, 0.U(0.W).asInstanceOf[O], false )

} 

/** Counter模块实例化
 * @group module
 */
object Counter {
  def apply[V<:Bits with Num[V], O<:Bits with Num[O]]( init:V, max:V, min:V, num:Int, mode:UInt, op:O ) : CountImpl[V,O]
    = Count( init, max, min, num, mode, op, true )

  /** 0~log2Cell(load)循环计数 */
  def apply[V<:Bits with Num[V], O<:Bits with Num[O]]( load:V ):CountImpl[V,O]
    = apply( load, 0.U(0.W).asInstanceOf[V], 0.U(0.W).asInstanceOf[V], 1, CNT_MODE.LOOP, 0.U(0.W).asInstanceOf[O] )

  /** 0~max循环计数 */
  def apply[V<:Bits with Num[V], O<:Bits with Num[O]]( load:V, max:V ):CountImpl[V,O]
    = apply( load, max, 0.U(0.W).asInstanceOf[V], 1, CNT_MODE.LOOP, 0.U(0.W).asInstanceOf[O] )

  /** min~max饱和计数 */
  def apply[V<:Bits with Num[V], O<:Bits with Num[O]]( load:V, min:V, max:V ):CountImpl[V,O]
    = apply( load, max, min, 1, CNT_MODE.SAF, 0.U(0.W).asInstanceOf[O] )

  /** 0~max饱和计数 */
  def apply[V<:Bits with Num[V], O<:Bits with Num[O]]( load:V, max:V, num:Int ):CountImpl[V,O]
    = apply( load, max, 0.U(0.W).asInstanceOf[V], num, CNT_MODE.SAF, 0.U(0.W).asInstanceOf[O] )

  /** min~max饱和计数 */
  def apply[V<:Bits with Num[V], O<:Bits with Num[O]]( load:V, max:V, min:V, num:Int ):CountImpl[V,O]
    = apply( load, max, min, num, CNT_MODE.SAF, 0.U(0.W).asInstanceOf[O] )
}

/** Counters模块 
 * @group module
 */
class CountersImpl[V<:Bits with Num[V], O<:Bits with Num[O]]( v:V, op:O, cnum:Int, num:Int ) extends Module {
  val io = IO(new CountersIO(v, op, num, cnum))   // 接口
  val cnters = RegInit(VecInit(Seq.fill(cnum)(v)))     // 寄存器阵列
  val counts = Seq.fill(num)(Count[V,O]( v, 0.U(0.W).asInstanceOf[V], 0.U(0.W).asInstanceOf[V], num, CNT_MODE.SAF, op, false ))  // 计数器

  // 分配给各个counts计算
  for( i <- 0 until num ){
    val cid = io.cmds(i).cid
    // 全局配置寄存器
    counts(i).io.clear := false.B 
    counts(i).io.clearValue := 0.U.asInstanceOf[V]
    counts(i).io.force := false.B 
    counts(i).io.forceValue := 0.U.asInstanceOf[V]
    counts(i).io.mode := io.mode
    counts(i).io.min := io.min 
    counts(i).io.max := io.max

    // 操作数赋值
    counts(i).io.cmds := io.cmds.map { case x => 
      CommandIO(
        op, 
        Mux(cid===x.cid, x.cmd, CNT_CMD.INVALID), 
        x.value) }
    counts(i).io.load := cnters(cid)

    // 返回值赋值
    cnters(cid) := counts(i).io.value
  }
}

}
